Go言語でのLambda+API Gatewayの開発環境をRIEを使って構築する

Lambda+API Gateway(またはFunctional URL)の開発環境をGoで構築しようとすると、実際のhttpリクエストを投げた確認などをするのを含めてローカルで環境を作りたくなります。その時に便利なのがRIE(AWS Lambda Runtime Interface Emulator)なのですが、これをAirなどを含めた環境を作るのが以外と苦労するので、その備忘録を残しておこうと思います。

ざっくりスタックを書くと

  • Go 1.20
    • Air
  • Docker
  • Lambda(Dockerランタイム)
  • API Gateway
  • RIE(AWS Lambda Runtime Interface Emulator)
  • REST Client※HTTPクライアントはなんでもOKです

といった感じで、シンプルな名前を返すアプリケーションを作ってみたいと思います。

基本的なファイル・フォルダ構成はこんな感じにしています。

$ tree .
.
├── cmd
│   └── rie_sample
│       └── main.go
├── docker
│   └── development
│       ├── Dockerfile
│       └── entry.sh
├── docker-compose.yml
├── go.mod
├── go.sum
├── handle_request.go
├── http
│   └── request.http
└── tmp

まず、cmd/lambda/main.goには

package main

import (
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/t4traw/rie_sample"
)

func main() {
	lambda.Start(rie_sample.HandleRequest)
}

いつものlambda.Startに、HandleRequest関数を渡します。

HandleRequestは

package rie_sample

import (
	"context"
	"fmt"
)

type Event struct {
	Name string `json:"name"`
}

func HandleRequest(ctx context.Context, event Event) (string, error) {
	return fmt.Sprintf("Hello %s!", event.Name), nil
}

こんな感じのシンプルな内容にしています。ここまではいつも通りのlambdaでそのままデプロイしても動くシンプルなGoのコードです。

このGoのコードをDocker上でair経由で動かします。Dockerfileはこんな感じで

FROM --platform=linux/amd64 golang:1.22.3

ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie

RUN go install github.com/air-verse/air@latest

COPY . /workspace
WORKDIR /workspace

RUN go build -o /cmd/rie_sample ./cmd/rie_sample
RUN chmod +x /cmd/rie_sample

CMD ["air", "-c", ".air.toml"]

.air.tomlはこんな感じです。

root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./docker/development/entry.sh /cmd/rie_sample"
cmd = "go build -o /cmd/rie_sample ./cmd/rie_sample"
...省略...

airでたたいてるshは

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
  exec /usr/bin/aws-lambda-rie "$@"
else
  exec "$@"
fi

になります!

最後にdocker-compose.ymlを

services:
  main:
    build:
      context: .
      dockerfile: ./docker/development/Dockerfile
    platform: linux/amd64
    volumes:
      - .:/workspace
    ports:
      - "9000:8080"

これで準備が整いました🥳

さっそくdocker compose upしてみましょう!

$ docker compose up
[+] Running 1/0
 ✔ Container rie_sample-main-1  Created                                    0.0s
Attaching to main-1
main-1  |
main-1  |   __    _   ___
main-1  |  / /\  | | | |_)
main-1  | /_/--\ |_| |_| \_ v1.52.2, built with Go go1.22.3
main-1  |
main-1  | watching .
main-1  | watching cmd
main-1  | watching cmd/rie_sample
main-1  | watching docker
main-1  | watching docker/development
main-1  | watching http
main-1  | !exclude tmp
main-1  | building...
main-1  | running...
main-1  | 09 Jun 2024 03:04:44,827 [INFO] (rapid) exec '/cmd/rie_sample' (cwd=/workspace, handler=)

Dockerがたちあがったので、さっそくリクエストを送信してみたいと思います。

httpリクエストはcurlなどで送信しても良いのですが、ミライ工事ではVSCodeプラグイン『REST Client』を使っています。開発用のリクエストをファイルに残しておいたり、変数なども使えるのでとても便利です。こちらはまた別の機会に詳しく紹介したいと思います!

GET http://localhost:9000/2015-03-31/functions/function/invocations

{
  "name": "t4traw"
}

/2015-03-31/functions/function/invocationsに関しては、RIEで指定されているパスになるので、おまじないと思ってください。

このリクエストの結果、レスポンスがちゃんと返ってきました!

スクリーンショットの右側がレスポンスになっています。


Go言語でのLambda+API Gatewayの開発環境をRIEを使って構築する方法を紹介しました。

RIEを使うと実際のリクエストのエミュレートができるので、とても安心して開発する事ができます。

Lambdaの開発の時には是非使ってみてください。